<template>
	<div class="app-data-import-content">
		<a-upload-dragger
			v-model:fileList="fileList"
			name="file"
			:multiple="false"
			class="app-data-import__upload"
			:maxCount="1"
			:before-upload="beforeUpload"
			@remove="handleRemove"
		>
            <div v-if="!uploadInfo" class="import-info">
                <p class="ant-upload-drag-icon">
                    <img class="icon-link" src="/assets/img/icon-import.svg" />
                </p>
                <p class="ant-upload-text">{{ $t('function.dataimport.selectfile') }}</p>
                <p class="ant-upload-hint" v-if="uploading">
                    {{ $t('function.dataimport.nowupload') }}
                    {{ uploadedProgress }}%，
                    {{ $t('function.dataimport.toolarge') }}
                </p>
            </div>
            <div v-else class="import-upload-info">
                <p class="upload-info-title">
                    {{ `共上传 ${uploadInfo.total} 条数据，成功上传 ${uploadInfo.success} 条数据` }}
                </p>
                <p class="error" v-for="(error, index) in uploadInfo.errorinfo" :key="index" :title="error.info">
                    {{ `第 ${error.row} 行：${error.info}` }}
                </p>
            </div>
		</a-upload-dragger>
		<div class="app-data-import__describe">
			<div>{{ $t('function.dataimport.datatemplatemessage') }}</div>
			<span class="app-data-import__describe__link" @click="handleDownloadTemp">
				<img class="icon-link" src="/assets/img/icon-link.svg" />
				{{ viewParams ? viewParams.appDeLogicName : ''
				}}{{ $t('function.dataimport.datatemplate') }}
			</span>
		</div>
		<a-space align="end" class="app-data-import__footer">
			<a-button type="primary" @click="handleCancel(true)">{{
				$t('function.dataimport.cancel')
			}}</a-button>
			<a-button
				type="primary"
				:loading="uploading"
				:disabled="fileList.length === 0"
				@click="handleUpload"
				>{{ $t('function.dataimport.uploadserver') }}</a-button
			>
		</a-space>
	</div>
</template>

<script setup lang="ts">
import {
	IContext,
	IParam,
	ViewActionType,
	srfpluralize,
	ExportExcelUtil,
	deepCopy,
	ICodeListItem,
    IEvent,
} from '@/core';
import { UploadFile, UploadProps } from 'ant-design-vue';
import { PropType, Ref } from 'vue';
import axios from 'axios';
import XLSX from 'xlsx';
const props = defineProps({
	context: {
		type: Object as PropType<IContext>,
	},
	viewParams: {
		type: Object as PropType<IParam>,
	},
});
const emit = defineEmits<{
	(
		event: 'view-action',
		name: string,
		action: ViewActionType,
		data: any
	): void;
}>();
const fileList = ref<any[]>([]);
const uploading = ref<boolean>(false);
const uploadedProgress = ref<number>(0);
const uploadInfo: Ref<null | IParam> = ref(null);
const codeListMap: Map<string, ICodeListItem[]> = new Map();
const uploadSuccess = ref(false);
const uploaded = ref(false);
/**
 * 处理取消
 */
const handleCancel = (cancel: boolean = false) => {
    if (cancel) {
        emit('view-action', 'dataImport', 'viewClose', uploadSuccess.value ? fileList.value : null);
    } else {
        emit('view-action', 'dataImport', 'viewDataSave', uploadSuccess.value ? fileList.value : null);
    }
};

/**
 * 下载导入模板
 */
const handleDownloadTemp = () => {
	if (import.meta.env.VITE_MODE === 'R7') {
		handleDownloadTempWithOld();
	} else {
		handleDownloadTempWithNew();
	}
};

/**
 * 下载导入模板（R7标准模式）
 */
const handleDownloadTempWithOld = async () => {
	const importItems: IParam[] =
		props.viewParams && props.viewParams.importItems
			? props.viewParams.importItems
			: [];
	const tHeaders: string[] = importItems.map((item: IParam) => item.caption);
	const excel = await ExportExcelUtil.getInstance().getExcel();
	excel.export_json_to_excel({
		header: tHeaders, //表头 必填
		data: [], //具体数据 必填
		filename: `${props.viewParams && props.viewParams.appDeLogicName}${App.ts(
			'function.dataimport.datatemplate',
			'导入数据模板'
		)}`,
		autoWidth: true, //非必填
		bookType: 'xlsx', //非必填
	});
};

/**
 * 下载导入模板（Cloud标准模式）
 */
const handleDownloadTempWithNew = () => {
	let requestUrl = '';
	if (props.viewParams) {
		const { srfparentkey, srfparentdename, serviceName, importId } =
			props.viewParams;
		if (srfparentkey && srfparentdename && srfparentdename !== serviceName) {
			requestUrl += `/${srfpluralize(srfparentdename)}/${srfparentkey}`;
		}
		requestUrl += `/${srfpluralize(serviceName)}/importtemplate`;
		if (importId) {
			requestUrl += `?srfimporttag=${importId}`;
		}
	}
	axios({
		url: requestUrl,
		method: 'get',
		responseType: 'blob',
	}).then((response: any) => {
		if (response.status == 200) {
			let fileName = response.headers['content-disposition']
				.split(';')
				.find((str: string) => str.indexOf('filename=') != -1)
				?.slice(9);
			fileName = decodeURIComponent(fileName);
			let blob = new Blob([response.data], {
				type: 'application/vnd.ms-excel',
			});
			let elink = document.createElement('a');
			elink.download = fileName;
			elink.style.display = 'none';
			elink.href = URL.createObjectURL(blob);
			document.body.appendChild(elink);
			elink.click();
			URL.revokeObjectURL(elink.href); // 释放URL 对象
			document.body.removeChild(elink);
		}
	});
};

/**
 * 处理删除
 * @param file 文件
 */
const handleRemove: UploadProps['onRemove'] = (file: UploadFile<unknown>) => {
	if (fileList.value) {
		const index = fileList.value.indexOf(file);
		const newFileList = fileList.value.slice();
		newFileList.splice(index, 1);
		fileList.value = newFileList;
	}
};

/**
 * 上传之前
 * @param file 文件
 */
const beforeUpload: UploadProps['beforeUpload'] = (file: UploadFile<unknown>) => {
	fileList.value = [...(fileList.value || []), file];
	return false;
};

/**
 * 上传
 */
const handleUpload = () => {
    uploadInfo.value = null;
    uploaded.value = false;
	if (import.meta.env.VITE_MODE === 'R7') {
		handleUploadWithOld();
	} else {
		handleUploadWithNew();
	}
};

/**
 * 文件上传（R7标准模式）
 */
const handleUploadWithOld = () => {
	if (fileList.value && fileList.value.length > 0) {
		const file = fileList.value[0];
		const reader = new FileReader();
		reader.onload = (e: any) => {
			let data = e.target.result;
			const workBookData = XLSX.read(data, { type: 'binary', cellDates: true });
			let xlsxData: IParam[] = XLSX.utils.sheet_to_json(
				workBookData.Sheets[workBookData.SheetNames[0]]
			);
			let list = getFirstRow(workBookData);
			xlsxData = transformImportData(xlsxData, list);
			handleSliceUpload(xlsxData);
		};
		reader.readAsBinaryString(file.originFileObj);
	}
};
/**
 * 初始化代码表数据
 */
const initCodeListData = async (): Promise<void> => {
	const importItems =
		props.viewParams && props.viewParams.importItems
			? props.viewParams.importItems
			: [];
	for (const item of importItems) {
		if (item.codeListTag) {
			const result = await App.getAppCodeListHelper().getCodeListItems(
				item.codeListTag,
				props.context,
				{ page: 0, size: 10000 }
			);
			if (result.ok) {
				codeListMap.set(item.name, result.data);
			}
		}
	}
};
initCodeListData();
/**
 * 切片上传
 * @param data 上传数据
 */
const handleSliceUpload = async (data: IParam[]) => {
	uploadedProgress.value = 0;
	if (!props.viewParams) {
		return;
	}
	if (!props.viewParams.serviceName) {
		App.getNotificationHelper().warning(
			'',
			App.ts('function.dataimport.notservice', '未配置实体服务')
		);
		return;
	}
	//	开始上传
	uploading.value = true;
	const dataService = await App.getDataService(
		props.viewParams.serviceName,
		props.context
	);
	const sliceSize = App.getProjectSetting().sliceUploadCnt || 500;
	const { importId, ignoreError } = props.viewParams;
	const sliceUpload = async (cnt: number) => {
		if (cnt >= data.length) {
			//	上传完成
			uploading.value = false;
            uploadSuccess.value = true;
            uploaded.value = true;
			App.getNotificationHelper().success(
				App.ts('function.dataimport.read'),
				App.ts('function.dataimport.completed')
			);
			handleCancel();
			return;
		}
		const sliceData = data.slice(cnt, cnt + sliceSize);
		try {
			const response = await dataService.importData(props.context, {
				name: importId,
				ignoreError,
				importData: sliceData,
			});
            const { errorinfo } = response.data;
            handleUploadInfo(response.data);
			if (errorinfo && errorinfo.length > 0) {
				if (!ignoreError) {
                    uploadSuccess.value = false;
					uploading.value = false;
                    uploaded.value = true;
					return;
				}
			}
			uploadedProgress.value = Number(((cnt / data.length) * 100).toFixed(2));
			await sliceUpload(cnt + sliceSize);
		} catch (error: any) {
            let uploadInfo: IParam = {
                total: 0,
                success: 0,
                errorinfo: error.errorinfo ? error.errorinfo : []
            }
            handleUploadInfo(uploadInfo);
			if (error.errorinfo && error.errorinfo.length > 0) {
				if (!ignoreError) {
                    uploadSuccess.value = false;
					uploading.value = false;
                    uploaded.value = true;
					return;
				}
			}
			uploadedProgress.value = Number(((cnt / data.length) * 100).toFixed(2));
			await sliceUpload(cnt + sliceSize);
		}
	};
	sliceUpload(0);
};
/**
 * 处理上传信息
 * @param infos 上传提示信息
 */
const handleUploadInfo = (uploadinfo: IParam) => {
    uploadInfo.value = uploadinfo;
};
/**
 * 获取第一行内容(并翻译属性字段)
 * @param wb 工作表
 */
const getFirstRow = (wb: XLSX.WorkBook) => {
	// 读取的excel单元格内容
	let wbData = wb.Sheets[wb.SheetNames[0]];
	// 匹配excel第一行的内容
	let re = /^[A-Z]1$/;
	let textArr: string[] = [];
	// excel第一行内容赋值给数组
	for (let key in wbData) {
		if (wbData.hasOwnProperty(key)) {
			if (re.test(key)) {
				textArr.push(wbData[key].h);
			}
		}
	}
	return textArr;
};
/**
 * 翻译导入数据
 * @param xlsxData xlsx数据
 * @param list 第一行内容
 */
const transformImportData = (xlsxData: IParam[], list: string[]) => {
    let filedArr: IParam[] = transformField(list);
    let result: IParam[] = [];
	for (let i = 0; i < xlsxData.length; i++) {
        const row: IParam = {};
        filedArr.forEach((field: IParam) => {
            Object.assign(row, {
                [field.fieldName]: null
            })
        })
		for (let j = 0; j < filedArr.length; j++) {
            const fieldName = filedArr[j].fieldName;
            let value = xlsxData[i][filedArr[j].text];
            if (value && fieldName) {
                const codeList: ICodeListItem[] | undefined = codeListMap.get(fieldName);
                if (codeList && codeList.length > 0) {
                    const item: ICodeListItem | undefined = codeList.find((item: ICodeListItem) => {
                        return item.text === value;
                    })
                    if (item) {
                        value = item.value;
                    }
                }
                Object.assign(row, {
                    [fieldName]: value
                })
            }
		}
        result.push(row);
	}
	return result;
};
/**
 * 翻译数据（数据字段翻译）
 * @param textArr 导入第一行标题文本
 */
const transformField = (textArr: string[]): IParam[] => {
    let result: IParam[] = [];
	const importItems =
		props.viewParams && props.viewParams.importItems
			? props.viewParams.importItems
			: [];
    textArr.forEach((text: string) => {
        const importItem = importItems.find((importItem: any) => {
            return importItem.caption === text;
        });
        if (importItem && importItem.fieldCodeName) {
            result.push({ text: text, fieldName: importItem.fieldCodeName });
        }
    })
	return result;
};
/**
 * 上传（cloud标准模式）
 */
const handleUploadWithNew = () => {
	if (fileList.value) {
		let requestUrl = '';
		if (props.viewParams) {
			const { srfparentkey, srfparentdename, serviceName, importId } =
				props.viewParams;
			if (
				srfparentkey &&
				srfparentdename &&
				srfparentdename.toLowerCase() !== serviceName.toLowerCase()
			) {
				requestUrl += `/${srfpluralize(srfparentdename)}/${srfparentkey}`;
			}
			requestUrl += `/${srfpluralize(
				serviceName.toLowerCase()
			)}/importtemplate`;
			if (importId) {
				requestUrl += `?srfimporttag=${importId}`;
			}
		}
		const data = new FormData();
		data.append('file', fileList.value[0].originFileObj);
        let uploadInfo: IParam = {
            total: 0,
            success: 0,
            errorinfo: []
        }
		axios
			.post(requestUrl, data, {
				headers: { 'Content-Type': 'multipart/form-data' },
				onUploadProgress: (progressEvent: any) => {
					uploadedProgress.value = Math.floor(
						(progressEvent.loaded / progressEvent.total) * 100
					);
				},
			})
			.then((res: any) => {
				if (res && res.status && res.status == 200) {
					const { data: data } = res;
					fileList.value = [];
					uploading.value = false;
                    uploaded.value = true;
					if (props.viewParams && props.viewParams.ignoreError) {
						if (
							data &&
							Object.prototype.toString.call(data) === '[object Object]' &&
							Object.keys(data).length > 0
						) {
                            
							Object.keys(data).forEach((key: string) => {
                                uploadInfo.total += uploadInfo.total
                                if (data[key]['errorInfo']) {
                                    uploadInfo.push({
                                        row: key + 1,
                                        info: `${data[key]['errorInfo']}`
                                    })
                                } else {
                                     uploadInfo.success += uploadInfo.success
                                }
							});
                            handleUploadInfo(uploadInfo);
						}
					} else {
						App.getNotificationHelper().success(
							App.ts('function.dataimport.read'),
							App.ts('function.dataimport.completed')
						);
                        uploadSuccess.value = true;
						handleCancel();
					}
				}
			})
			.catch((error: any) => {
				uploading.value = false;
                uploadSuccess.value = false;
                uploaded.value = true;
				if (error && error.status && error.status !== 200) {
					App.getNotificationHelper().error(
						App.ts('common.generic.error'),
						error.data?.message
					);
				}
			});
	}
};
</script>
